'use strict';


const Service = require('egg').Service;

const ConnectOption = require('../oltmodules/ConnectOption');
const ZTEOLT = require('../oltmodules/ZTEOLT');
const HWOLT = require('../oltmodules/HuaWeiOLT');
const ulid = require('../public/ulid');
const XDOLT = require('../oltmodules/XinDeOLT');
const XGLOLT = require('../oltmodules/XinGeLinOLT');
class OnuFindListService extends Service {
  async list(params) {
    // const tid = params.tid;
    const result = {
      count: '',
      rows: '',
    };
    if (params.oltId) {
      result.count = await this.ctx.model.OnuFind.find({ oltId: params.oltId, tid: params.tid }).count('_id');
      result.rows = await this.ctx.model.OnuFind.aggregate([
        {
          $match: {
            tid: params.tid,
            oltId: params.oltId,
          },
        },
        {
          $lookup: { // 左连接
            from: 'olt', // 关联到olt表
            localField: 'oltId', // oltType 表关联的字段
            foreignField: '_id', // script 表关联的字段
            as: 'olt',
          },
        },
      ]).sort('slot').sort('port')
        .sort('number')
        .skip(parseInt((params.page - 1) * params.limit))
        .limit(parseInt(params.limit));
      return result;
    }
    result.count = await this.ctx.model.OnuFind.find({ tid: params.tid }).count('_id');
    result.rows = await this.ctx.model.OnuFind.aggregate([
      {
        $match: {
          tid: params.tid,
        },
      },
      {
        $lookup: { // 左连接
          from: 'olt', // 关联到olt表
          localField: 'oltId', // oltType 表关联的字段
          foreignField: '_id', // script 表关联的字段
          as: 'olt',
        },
      },
    ]).sort('oltId').sort('slot')
      .sort('port')
      .sort('number')
      .skip(parseInt((params.page - 1) * params.limit))
      .limit(parseInt(params.limit));
    return result;

  }
  async refresh(params) {
    const tid = params.tid;
    if (params.oltId) {
      const result = await onufindlistrefresh(params.oltId, this);
      if (result.status == 17) {
        return result.msg;
      }
      // 删除onu数据库
      const olt = await this.ctx.model.Olt.findOne({ where: { id: params.oltId } });
      const onufindarr = await sortONUFindIndex(olt.oltType, olt.id, result, this);
      await this.ctx.model.OnuFind.destroy({ where: [{ oltId: params.oltId }] });
      await this.ctx.model.OnuFind.bulkCreate(onufindarr);
      result.msg = olt.oltIP + 'refresh successful';
      return result;

    }
    const alloltresult = {
      success: '',
      fail: '',
    };
    const oltlist = await this.ctx.model.Olt.findAll({
      where: { tid },
    });
    for (let i = 0; i < oltlist.length; i++) {
      const result = await onufindlistrefresh(oltlist[i].id, this);
      if (result.status == 17) {
        alloltresult.fail += result.msg + '';
        continue;
      } else {
        alloltresult.success += oltlist[i].oltIP + 'refresh successful';
        const onufindarr = await sortONUFindIndex(oltlist[i].oltType, oltlist[i].id, result, this);
        // 删除数据
        await this.ctx.model.OnuFind.destroy({ where: { oltId: oltlist[i].id } });
        // 添加数据
        await this.ctx.model.OnuFind.bulkCreate(onufindarr);
      }
    }
    return alloltresult;

  }
  async onufindcreate(params) {
    // olt信息
    const tid = params.tid;
    const onuFindResult = await this.ctx.model.OnuFind.findOne({ _id: params.id });
    const oltInformation = await this.ctx.model.Olt.findOne({ _id: onuFindResult.oltId });
    const options = new ConnectOption(oltInformation.oltIP, oltInformation.initCommunity, oltInformation.snmpUDPPort, 162, true, true, oltInformation.telnetTCPPort, oltInformation.oltManagementPassword, oltInformation.oltTelnetUsername, oltInformation.oltTelnetPassword, oltInformation.systemName, oltInformation.RZUsername, oltInformation.RZPassword,oltInformation.telnetProxySwitch);
    // 注册onu
    let onuresult;
    const result = {
      msg: '',
    };
    try {
      switch (oltInformation.oltType) {
        case 'OPTICTIMES':
        { const ONUProfileResult = await this.ctx.model.OnuProfile.findOne({ where: { id: params.onuProfileId } });
          const ONUProfileName = ONUProfileResult.Pname;
          // if (params.uplinkId == 'default') {
          //   var uplink = 'default';
          // } else {
          //   const uplinkResult = await this.ctx.model.SpeedTemplate.findOne({ where: { id: params.uplinkId } });
          //   var uplink = uplinkResult.name;
          // }
          // if (params.downId == 'default') {
          //   var down = 'default';
          // } else {
          //   const downResult = await this.ctx.model.SpeedTemplate.findOne({ where: { id: params.downId } });
          //   var down = downResult.name;
          // }
          const uplinkResult = await this.ctx.model.SpeedProfile.findOne({ _id: params.uplinkId });
          const uplink = uplinkResult.name;
          const downResult = await this.ctx.model.SpeedProfile.findOne({ _id: params.downId });
          const down = downResult.name;
          const xd = new XDOLT(options);
          onuresult = await xd.setONU(params.ONUindex, params.PONindex, ONUProfileName, params.mode, params.vlan, uplink, down, params.ONUname, params.sn, oltInformation.oltHardVersion, this);
          if (onuresult != true) {
            if (onuresult[0].indexOf('profile traffic') != -1) {
              await xd.deleteONU(params.PONindex, params.ONUindex, oltInformation.oltHardVersion, this);
              result.msg = 'onu create fail,' + onuresult[0];
              return result;
            }
            result.msg = 'onu create fail,' + onuresult[0];
            return result;

          }
          break; }
        case 'ZTE': {
          const PONOLTName = params.PONindex.replace('-onu', '-olt');
          const lineProfileResult = await this.ctx.model.LineProfile.findOne({ _id: params.lineProfileId });
          const lineProfileName = lineProfileResult.name;
          const remoteProfileResult = await this.ctx.model.RemoteProfile.findOne({ _id: params.remoteProfileId })
          const remoteProfileName = remoteProfileResult.name;
          const lineProfileBusiness = lineProfileResult.bussinessArr;
          const remoteProfileBusiness = remoteProfileResult.bussinessArr;
          console.log('test lineprofile', lineProfileResult, params.lineProfileId);
          // onuprofile 例子：ZTE-F625
          const ONUProfileResult = await this.ctx.model.OnuProfile.findOne({ _id: params.onuProfileId });
          const ONUProfileName = ONUProfileResult.Pname;
          const zte = new ZTEOLT(options);
          onuresult = await zte.setONU(params.ONUindex, params.PONindex, PONOLTName, ONUProfileName, params.ONUname, params.sn, oltInformation.oltHardVersion, oltInformation.ACSVlan, lineProfileName,remoteProfileName, remoteProfileBusiness, this);
          console.log('setONU函数返回', onuresult);
          if (onuresult !== true) {
            if (onuresult[0] === 'DBA profile or Uplink/Down speed does not exist') {
              await zte.deleteONU(PONOLTName, params.ONUindex, oltInformation.oltHardVersion, this);
              result.msg = 'onu create fail,' + onuresult[0];
              return result;
            }
            result.msg = 'onu create fail,' + onuresult[0];
            return result;

          }
          break; }
        case 'HUAWEI': {
          // lineprofile
          const lineProfileResult = await this.ctx.model.LineProfile.findOne({ _id: params.lineProfileId });
          const lineprofile = lineProfileResult.name;
          const lineProfileBusiness = Array.isArray(params.lineProfileJSON)?params.lineProfileJSON:[params.lineProfileJSON];
          // const lineProfileBusiness = lineProfileResult.bussinessArr;
          // srvprofile
          const srvProfileResult = await this.ctx.model.OnuProfile.findOne({ _id: params.srvProfileId });
          const srvprofile = srvProfileResult.Pname;
          const hw = new HWOLT(options);
          onuresult = await hw.setONU(params.PONindex, params.ONUindex, params.sn, lineprofile, srvprofile, params.ONUname, oltInformation.ACSVlan, lineProfileBusiness, this);
          if (onuresult !== true) {
            if (onuresult[0] === 'The GEM index does not exist' || onuresult[0] === 'VLAN does not exist' || onuresult === 'The traffic table does not exist') {
              // 删除onu
              await hw.deleteONU(params.PONindex, params.ONUindex, null, oltInformation.oltHardVersion, this);
              result.msg = 'onu create fail,' + onuresult[0];
              return result;
            }
            result.msg = 'onu create fail,' + onuresult[0];
            return result;

          }
          break;
        }
        case 'XINGELIN':
        // 上行
        // var uplinkResult = await this.ctx.model.SpeedTemplate.findOne({ where: { id: params.uplinkId } });
        // var uplink = uplinkResult.name;
        // // 下行
        // var downResult = await this.ctx.model.SpeedTemplate.findOne({ where: { id: params.downId } });
        // var down = downResult.name;
        // lineprofile
        { const lineProfileResult1 = await this.ctx.model.LineProfile.findOne({ where: { id: params.lineProfileId } });
          const lineprofile = lineProfileResult1.PID;
          const xgl = new XGLOLT(options);
          const uplinkResult = await this.ctx.model.SpeedProfile.findOne({ _id: params.uplinkId });
          const uplink = uplinkResult.name;
          const downResult = await this.ctx.model.SpeedProfile.findOne({ _id: params.downId });
          const down = downResult.name;
          onuresult = await xgl.setONU(params.PONindex, params.ONUindex, params.sn, uplink, down, lineprofile, params.ONUname, oltInformation.oltHardVersion, this);
          if (onuresult !== true) {
            if (onuresult[0] === 'The profile entry name is invalid') {
              // 删除onu
              await xgl.deleteONU(params.PONindex, params.ONUindex, oltInformation.oltHardVersion, this);
              result.msg = 'onu create fail,' + onuresult[0];
              return result;
            }
            result.msg = 'onu create fail,' + onuresult[0];
            return result;

          }
          break; }
        default:
          break;
      }
      console.log('注册onu 返回：', onuresult);
      if (onuresult) {
        // 删除onufind里面的onu
        await this.ctx.model.OnuFind.deleteOne({ _id: params.id });
        await this.ctx.model.OnuList.create({
          _id: ulid.ulid(),
          onlyindex: params.PONindex + ':' + params.ONUindex,
          PONindex: params.PONindex,
          ONUindex: params.ONUindex,
          ONUname: params.ONUname,
          sn: params.sn,
          oltId: onuFindResult.oltId,
          status: 'OnLine',
          number: params.ONUindex,
          slot: params.PONindex.split('/')[1],
          port: params.PONindex.split('/')[2],
          tid,
        });
        result.msg = 'onu create successful';
      }
      return result;
    } catch (error) {
      result.msg = error.message;
      return result;
    }
  }
}
async function onufindlistrefresh(oltId, me) {
  // 查询olt
  const result = {
    msg: '',
    status: '',
  };
  const oltresult = await me.ctx.model.Olt.findOne({
    where: { id: oltId },
  });
  const oltstate = await isOnline(oltresult);
  if (oltstate == false) {
    result.msg = oltresult.oltIP + 'olt is offline';
    result.status = 17;
    return result;
  }
  const options = new ConnectOption(oltresult.oltIP, oltresult.snmpReadOnlyCommunity, oltresult.snmpUDPPort, 162, true, true, oltresult.telnetTCPPort, oltresult.oltManagementPassword, oltresult.oltTelnetUsername, oltresult.oltTelnetPassword, oltresult.systemName, oltresult.RZUsername,oltresult.RZPassword,oltresult.telnetProxySwitch);
  let onufindarr;
  switch (oltresult.oltType) {
    case 'OPTICTIMES':
      const xd = new XDOLT(options);
      onufindarr = await xd.getonufind_XD(oltresult.oltHardVersion, me);
      break;
    case 'ZTE':
      const zte = new ZTEOLT(options);
      onufindarr = await zte.getonufind_ZTE(oltresult.oltHardVersion, me);
      break;
    case 'HUAWEI':
      const hw = new HWOLT(options);
      onufindarr = await hw.getonufind_HW(oltresult.oltHardVersion, me);
      break;
    case 'XINGELIN':
      const xgl = new XGLOLT(options);
      onufindarr = await xgl.getonufind_XGL(oltresult.oltHardVersion, me);
      break;
    default:
      break;
  }
  return onufindarr;

}
async function isOnline(oltInformation) {
  const options = new ConnectOption(
    oltInformation.oltIP,
    oltInformation.initCommunity,
    oltInformation.snmpUDPPort,
    162,
    true,
    true,
    oltInformation.telnetTCPPort,
    oltInformation.oltManagementPassword,
    oltInformation.oltTelnetUsername,
    oltInformation.oltTelnetPassword,
    oltInformation.systemName,
    oltInformation.RZUsername,
    oltInformation.RZPassword,
    oltInformation.telnetProxySwitch
  );
  let result = false;
  switch (oltInformation.oltType) {
    case 'FIBERHOME':
      break;
    case 'OPTICTIMES':
      const xd = new XDOLT(options);
      result = await xd.XDTestConnection();
      break;
    case 'ZTE':
      const zte = new ZTEOLT(options);
      result = await zte.ZTETestConnection();
      break;
    case 'HUAWEI':
      const hw = new HWOLT(options);
      result = await hw.HWTestConnection();
      break;
    case 'XINGELIN':
      const xgl = new XGLOLT(options);
      result = await xgl.XGLTestConnection();
      break;
    default:
      break;
  }
  return result;
}
async function sortONUFindIndex(oltType, oltID, result, me) {
  let ponindex = '';
  let j = 0;
  for (let i = 0; i < result.length; i++) {
    if (ponindex != result[i].PONindex) {
      j = 0;
      ponindex = result[i].PONindex;
      result[i].index = await setONUindex(oltType, oltID, result[i].PONindex, j, me);
      j++;
    } else {
      result[i].index = await setONUindex(oltType, oltID, result[i].PONindex, j, me);
      j++;
    }
    result[i].id = ulid.ulid();
    result[i].oltId = oltID;
  }
  return result;
}
async function setONUindex(oltType, oltID, PONindex, index, me) {
  let result;
  const onulistarr = [];
  const arr = [];
  const delta1 = oltType == 'HUAWEI' ? 0 : 1;
  const delta2 = oltType == 'HUAWEI' ? 127 : 128;
  for (let i = delta1; i <= delta2; i++) {
    arr.push(i);
  }
  const Onu = await me.ctx.model.Onu.findAll({ where: [{ oltId: oltID }, { PONindex }], order: [[ 'ONUindex', 'DESC' ]] });
  for (let j = 0; j < Onu.length; j++) {
    onulistarr.push(parseInt(Onu[j].ONUindex)); // 数据库里的ONUindex
  }
  const remainArr = getSubArray(arr, onulistarr);
  result = remainArr[index];
  return result;
}
function getSubArray(arr1, arr2) {
  const set1 = new Set(arr1);
  const set2 = new Set(arr2);
  const result = [];
  set1.forEach((item, index) => {
    if (!set2.has(item)) {
      result.push(item);
    }
  });
  return result;
}
module.exports = OnuFindListService;
